//
//  graphics.m
//  iCodeMacRun
//
//  Created by Andrew Barry on 30/03/09.
//  Copyright 2009 Barry Computer Services. All rights reserved.
//

#import "graphics.h"

#ifdef MACOSX
NSColor *gFillColor = nil;
NSColor *gColor = nil;
#endif

jsvalue imageConstructor(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	if (argc == 0)
		return JSVAL_VOID;
	
	double w=32, h=32;
	
	if (argc >= 1)
		w = h = jsasnum(cx, argv[0]);
	if (argc >= 2)
		h = jsasnum(cx, argv[1]);

#ifdef MACOSX
	NSImage *img = [[NSImage alloc] initWithSize:NSMakeSize(w, h)];
	idToObject(cx, obj, img);
#endif					
	return JSVAL_VOID;
}

void cocoaImageFinalizer(jscontext *cx, jsobject *obj) {
	printf("image finalize\n");
}

jsvalue imageLockMethod(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
#ifdef MACOSX
	NSImage *img = idFromObject(cx, obj);
	[img lockFocus];
#endif
	return JSVAL_VOID;
}

jsvalue imageUnlockMethod(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
#ifdef MACOSX
	NSImage *img = idFromObject(cx, obj);
	[img unlockFocus];
#endif
	return JSVAL_VOID;
}
/*
JSClass cocoaImageClass = {"Image", JSCLASS_HAS_RESERVED_SLOTS(1), 
JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,JS_PropertyStub, 
JS_EnumerateStub,JS_ResolveStub,JS_ConvertStub,cocoaImageFinalizer 
};

JSPropertySpec cocoaImageProps[] = {
{0, 0, 0, 0, 0}
};

JSFunctionSpec cocoaImageFunctions[] = {
{"lock", imageLockMethod, 0, 0, 0 },
{"unlock", imageUnlockMethod, 0, 0, 0 },
{0, 0, 0, 0, 0}
};
*/

static jsvalue drawLine(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	if (argc < 4)
		return JSVAL_VOID;

	double x1, y1, x2, y2;
	x1 = jsasnum(cx, argv[0]);
	y1 = jsasnum(cx, argv[1]);
	x2 = jsasnum(cx, argv[2]);
	y2 = jsasnum(cx, argv[3]);


#ifdef MACOSX
	if (gColor)
		[gColor set];
	else
		[[NSColor blackColor] set];
	[NSBezierPath strokeLineFromPoint:NSMakePoint(x1, y1) toPoint:NSMakePoint(x2, y2)];
#endif

#ifdef PHONEOSX
	CGContextRef ctx = UIGraphicsGetCurrentContext();
	CGContextMoveToPoint(ctx, x1, y1);
	//add a line from 0,0 to the point 100,100
	CGContextAddLineToPoint( ctx, x2,y2);
	//"stroke" the path
	CGContextStrokePath(ctx);
#endif
	
	return JSVAL_VOID;
}

static jsvalue drawOval(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	if (argc < 4)
		return JSVAL_VOID;
	
	double x1, y1, w, h;
	x1 = jsasnum(cx, argv[0]);
	y1 = jsasnum(cx, argv[1]);
	w = jsasnum(cx, argv[2]);
	h = jsasnum(cx, argv[3]);

#ifdef MACOSX	
	NSBezierPath *path = [NSBezierPath bezierPathWithOvalInRect:NSMakeRect(x1, y1, w, h)];

	if (gColor)
		[gColor set];
	else
		[[NSColor blackColor] set];
	
	[path stroke];
#endif
	return JSVAL_VOID;
}

static jsvalue drawSetLineWidth(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	if (argc < 1)
		return JSVAL_VOID;
	
	double v = jsasnum(cx, argv[0]);
	
#ifdef MACOSX	
	[NSBezierPath setDefaultLineWidth:v];
#endif		
	return JSVAL_VOID;
}

static jsvalue drawImage(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	if (argc < 3)
		return JSVAL_VOID;

	if (!JSVAL_IS_OBJECT(argv[0]))
		return JSVAL_VOID;
	
#ifdef MACOSX	
	/*
	if (!JS_InstanceOf(cx, img, &cocoaImageClass, nil))
		return JSVAL_VOID;
*/	
	NSImage *image = idFromObject(cx, argv[0]);

	double x, y;
	x = jsasnum(cx, argv[1]);
	y = jsasnum(cx, argv[2]);
	
	if (argc < 5) {
		[image drawAtPoint:NSMakePoint(x, y) fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
	} else {
		double w, h;
		w = jsasnum(cx, argv[3]);
		h = jsasnum(cx, argv[4]);
		[image drawInRect:NSMakeRect(x, y, w, h) fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
	}
#endif
	return JSVAL_VOID;
}

#ifdef MACOSX	
static void prepareAttributes(jscontext *cx, jsvalue v, NSDictionary **pattributes ) {
	double fontSize = 12;
	NSString *fontName = @"Courier";
	int underline = 0;
	int strikethrough = 0;
	
	if (v && JSVAL_IS_OBJECT(v)) {
		fontSize = jsgetdouble(cx, v, 0, "size", 12);
		fontName = jsgetstring(cx, v, 0, "font", @"Courier");
		underline = jsgetint(cx, v, 0, "underline", 0);
		strikethrough = jsgetint(cx, v, 0, "strikethrough", 0);
	}
	
	*pattributes = [NSDictionary dictionaryWithObjectsAndKeys:
								[NSFont fontWithName: fontName size:fontSize],
								NSFontAttributeName,
								[NSNumber numberWithInt:underline],
								NSUnderlineStyleAttributeName,
								[NSNumber numberWithInt:strikethrough],
								NSStrikethroughStyleAttributeName,
								gColor ? gColor : [NSColor blackColor],
								NSForegroundColorAttributeName,
								nil ];
}
#endif

static jsvalue drawString(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	if (argc < 3)
		return JSVAL_VOID;
#ifdef MACOSX
	NSString *txt = jsasstrRetain(cx, argv[0]);
	NSDictionary* attributes;
	
	prepareAttributes(cx, argc >= 3 ? argv[3] : JSVAL_VOID, &attributes );

	double x, y;
	x = jsasnum(cx, argv[1]);
	y = jsasnum(cx, argv[2]);

	[txt drawAtPoint:NSMakePoint(x, y) withAttributes:attributes];
	[gFillColor setFill];
	[gColor set];
	[txt release];
#endif
	return JSVAL_VOID;
}

static jsvalue drawStringWidth(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	if (argc < 1)
		return JSVAL_VOID;

	NSString *txt = jsasstrRetain(cx, argv[0]);
	NSDictionary* attributes;
	jsvalue rv = JSVAL_VOID;
#ifdef MACOSX
	prepareAttributes(cx, argc >= 1 ? argv[1] : JSVAL_VOID, &attributes );

	NSSize sz = [txt sizeWithAttributes:attributes];
	
	rv = jsnum(cx, sz.width);
#endif	
	[txt release];
	return rv;
}

static jsvalue drawStringHeight(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	if (argc < 1)
		return JSVAL_VOID;
	jsvalue rv = JSVAL_VOID;
#ifdef MACOSX
	NSString *txt = jsasstrRetain(cx, argv[0]);
	NSDictionary* attributes;
	
	prepareAttributes(cx, argc >= 1 ? argv[1] : JSVAL_VOID, &attributes );
	
	NSSize sz = [txt sizeWithAttributes:attributes];
	rv = jsnum(cx, sz.height);
#endif
	[txt release];
	return rv;
}

static jsvalue drawRotate(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	if (argc < 1)
		return JSVAL_VOID;
#ifdef MACOSX
	double rot = jsasnum(cx, argv[0]);
	NSAffineTransform *tx = [NSAffineTransform transform];
	[tx rotateByDegrees:rot];
	[tx concat];
#endif
	return JSVAL_VOID;
}

static jsvalue drawTranslate(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	if (argc < 2)
		return JSVAL_VOID;
#ifdef MACOSX
	double dx = 0.0, dy = 0.0;
	dx = jsasnum(cx, argv[0]);
	dy = jsasnum(cx, argv[1]);
	NSAffineTransform *tx = [NSAffineTransform transform];
	[tx translateXBy:dx yBy:dy];
	[tx concat];
#endif
	return JSVAL_VOID;
}

static jsvalue drawScale(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	if (argc < 1)
		return JSVAL_VOID;
#ifdef MACOSX
	double dx = 0.0, dy = 0.0;
	dx = jsasnum(cx, argv[0]);
	if (argc > 1)
		dy = jsasnum(cx, argv[1]);
	else
		dy = dx;
	NSAffineTransform *tx = [NSAffineTransform transform];
	[tx scaleXBy:dx yBy:dy];
	[tx concat];
#endif
	return JSVAL_VOID;
}

#ifdef MACOSX
NSBezierPath *gCurrentPath = nil;
bool gCurrentPathHasMoveTo = false;
#endif

static jsvalue drawBeginPath(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
#ifdef MACOSX
	if (gCurrentPath)
		[gCurrentPath release];
	gCurrentPath = [[NSBezierPath alloc] init];
	gCurrentPathHasMoveTo = false;
#endif
	return JSVAL_VOID;
}

static jsvalue drawClosePath(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
#ifdef MACOSX
	if (gCurrentPath) {
		[gCurrentPath closePath];
	}
#endif
	return JSVAL_VOID;
}

static jsvalue drawMoveTo(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	if (argc < 2)
		return JSVAL_VOID;
#ifdef MACOSX
	double dx = 0.0, dy = 0.0;
	dx = jsasnum(cx, argv[0]);
	dy = jsasnum(cx, argv[1]);
	[gCurrentPath moveToPoint:NSMakePoint(dx, dy)];
	gCurrentPathHasMoveTo = true;
#endif
	return JSVAL_VOID;
}

static jsvalue drawLineTo(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	if (argc < 2)
		return JSVAL_VOID;
#ifdef MACOSX
	double dx = 0.0, dy = 0.0;
	dx = jsasnum(cx, argv[0]);
	dy = jsasnum(cx, argv[1]);
	if (!gCurrentPathHasMoveTo) {
		[gCurrentPath moveToPoint:NSMakePoint(0, 0)];
		gCurrentPathHasMoveTo = true;
	}
	[gCurrentPath lineToPoint:NSMakePoint(dx, dy)];
#endif
	return JSVAL_VOID;
}

static jsvalue drawArcTo(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	if (argc < 5)
		return JSVAL_VOID;
#ifdef MACOSX
	double dx = 0.0, dy = 0.0, radius = 0.0;
	double startAngle = 0.0, endAngle = 0.0;
	dx = jsasnum(cx, argv[0]);
	dy = jsasnum(cx, argv[1]);
	radius = jsasnum(cx, argv[2]);
	startAngle = jsasnum(cx, argv[3]);
	endAngle = jsasnum(cx, argv[4]);
	[gCurrentPath appendBezierPathWithArcWithCenter:NSMakePoint(dx, dy) radius:radius startAngle:startAngle endAngle:endAngle];
	gCurrentPathHasMoveTo = true;
#endif
	return JSVAL_VOID;
}

static jsvalue setFillColor(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	if (argc < 3)
		return JSVAL_VOID;

#ifdef MACOSX
	double r = 0.0, g = 0.0, b = 0.0;
	double alpha = 1.0;
	r = jsasnum(cx, argv[0]);
	g = jsasnum(cx, argv[1]);
	b = jsasnum(cx, argv[2]);
	if (argc > 3)
		alpha = jsasnum(cx, argv[3]);
	
	NSColor *col = [NSColor colorWithDeviceRed:r green:g blue:b alpha:alpha];
	[gFillColor release];
	gFillColor = [col retain];
#endif
	return JSVAL_VOID;
}

static jsvalue setColor(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	if (argc < 3)
		return JSVAL_VOID;
#ifdef MACOSX
	double r = 0.0, g = 0.0, b = 0.0;
	double alpha = 1.0;
	r = jsasnum(cx, argv[0]);
	g = jsasnum(cx, argv[1]);
	b = jsasnum(cx, argv[2]);
	if (argc > 3)
		alpha = jsasnum(cx, argv[3]);
	NSColor *col = [NSColor colorWithCalibratedRed:r green:g blue:b alpha:alpha];
	[gColor release];
	gColor = [col retain];
#endif
	return JSVAL_VOID;
}

static jsvalue drawStrokePath(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
#ifdef MACOSX
	if (gColor)
		[gColor set];
	else
		[[NSColor blackColor] set];
	[gCurrentPath stroke];
#endif
	return JSVAL_VOID;
}

static jsvalue drawFillPath(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
#ifdef MACOSX
	if (gFillColor)
		[gFillColor setFill];
	else
		[[NSColor blackColor] setFill];
	[gCurrentPath fill];
#endif
	return JSVAL_VOID;
}

jsvalue readImageFile(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {

	if (argc < 1)
		return JSVAL_VOID;
#ifdef MACOSX
	NSString *path = jsasstrRetain(cx, argv[0]);
	NSImage *img = [[NSImage alloc] initWithContentsOfFile:path];
	[path release];
	if (!img)
		return JSVAL_NULL;
	[img setFlipped:YES];
	return OBJECT_TO_JSVAL(bindImage(cx, img));
#endif
	return JSVAL_VOID;
}

void registerGraphics(jscontext *cx) {
	jsvalue Graphics, Image;
	cx->slots[16] = Graphics = jsnewobject(cx);
	cx->slots[17] = Image = bindFunction(cx, imageConstructor);
	
	jsset(cx, Graphics, 0, "line", bindFunction(cx, drawLine));
	jsset(cx, Graphics, 0, "image", bindFunction(cx, drawImage));
	jsset(cx, Graphics, 0, "string", bindFunction(cx, drawString));
	jsset(cx, Graphics, 0, "oval", bindFunction(cx, drawOval));
	
	jsset(cx, Graphics, 0, "rotate", bindFunction(cx, drawRotate));
	jsset(cx, Graphics, 0, "translate", bindFunction(cx, drawTranslate));
	jsset(cx, Graphics, 0, "scale", bindFunction(cx, drawScale));
	
	jsset(cx, Graphics, 0, "stringWidth", bindFunction(cx, drawStringWidth));
	jsset(cx, Graphics, 0, "stringHeight", bindFunction(cx, drawStringHeight));
	jsset(cx, Graphics, 0, "setLineWidth", bindFunction(cx, drawSetLineWidth));
	jsset(cx, Graphics, 0, "setFillColor", bindFunction(cx, setFillColor));
	jsset(cx, Graphics, 0, "setColor", bindFunction(cx, setColor));

	jsset(cx, Graphics, 0, "beginPath", bindFunction(cx, drawBeginPath));
	jsset(cx, Graphics, 0, "closePath", bindFunction(cx, drawClosePath));
	jsset(cx, Graphics, 0, "moveTo", bindFunction(cx, drawMoveTo));
	jsset(cx, Graphics, 0, "lineTo", bindFunction(cx, drawLineTo));
	jsset(cx, Graphics, 0, "arcTo", bindFunction(cx, drawArcTo));
	jsset(cx, Graphics, 0, "strokePath", bindFunction(cx, drawStrokePath));
	jsset(cx, Graphics, 0, "fillPath", bindFunction(cx, drawFillPath));

}

/*
jsobject *cocoaImageObject, *cocoaGfxObject;

void registerGraphics(jscontext *cx, jsobject *global) {
	JS_AddRoot(cx, &cocoaImageObject);

	cocoaImageObject = JS_InitClass(cx, global, NULL, &cocoaImageClass,
								   cocoaImageConstructor, 0,
								   cocoaImageProps,
								   cocoaImageFunctions, 
								   NULL, NULL);
	JS_AddRoot(cx, &cocoaGfxObject);
	
	cocoaGfxObject = JS_NewObject(cx, nil, nil, nil);
	JS_DefineProperty(cx, global, "Graphics", OBJECT_TO_JSVAL(cocoaGfxObject), NULL, NULL, JSPROP_READONLY | JSPROP_PERMANENT);
	
	JS_DefineFunction(cx, cocoaGfxObject, "line", drawLine, 4, 0);
	JS_DefineFunction(cx, cocoaGfxObject, "image", drawImage, 3, 0);
	JS_DefineFunction(cx, cocoaGfxObject, "string", drawString, 4, 0);
	JS_DefineFunction(cx, cocoaGfxObject, "oval", drawOval, 4, 0);

	JS_DefineFunction(cx, cocoaGfxObject, "rotate", drawRotate, 1, 0);
	JS_DefineFunction(cx, cocoaGfxObject, "translate", drawTranslate, 2, 0);
	JS_DefineFunction(cx, cocoaGfxObject, "scale", drawScale, 2, 0);

	JS_DefineFunction(cx, cocoaGfxObject, "stringWidth", drawStringWidth, 2, 0);
	JS_DefineFunction(cx, cocoaGfxObject, "stringHeight", drawStringHeight, 2, 0);
	JS_DefineFunction(cx, cocoaGfxObject, "setLineWidth", drawSetLineWidth, 1, 0);
	JS_DefineFunction(cx, cocoaGfxObject, "setFillColor", setFillColor, 3, 0);
	JS_DefineFunction(cx, cocoaGfxObject, "setColor", setColor, 3, 0);
	
	JS_DefineFunction(cx, cocoaGfxObject, "beginPath", drawBeginPath, 0, 0);
	JS_DefineFunction(cx, cocoaGfxObject, "closePath", drawClosePath, 0, 0);
	JS_DefineFunction(cx, cocoaGfxObject, "moveTo", drawMoveTo, 2, 0);
	JS_DefineFunction(cx, cocoaGfxObject, "lineTo", drawLineTo, 2, 0);
	JS_DefineFunction(cx, cocoaGfxObject, "arcTo", drawArcTo, 5, 0);
	JS_DefineFunction(cx, cocoaGfxObject, "strokePath", drawStrokePath, 0, 0);
	JS_DefineFunction(cx, cocoaGfxObject, "fillPath", drawFillPath, 0, 0);
}
*/
#ifdef MACOSX
jsobject *bindImage(jscontext *cx, NSImage *img) {
	jsvalue obj = jsnew(cx, cx->slots[17], nil, 0);
	idToObject(cx, obj, img);
	return obj;
}
#endif
#ifdef PHONEOSX
jsobject *bindImage(jscontext *cx, UIImage *img) {
	unimplemented();
/*
	jsobject *obj = JS_NewObject(cx, &cocoaImageClass, cocoaImageObject, nil);
	int v = (int) [img retain];
	
	JS_SetReservedSlot(cx, obj, 0, INT_TO_JSVAL(v));
	return obj;
 */
}
#endif
